/*
 * $AIST_Release: 0.9.0 $
 * Copyright 2011 Information Technology Research Institute, National
 * Institute of Advanced Industrial Science and Technology
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *    http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package generator

import java.io.File
import java.io.PrintWriter

import parser.Nodes._
import parser.DataTypes._
import parser.Results._
import parser.TreeWalker

/**
 * Module to generate source file where data types is defined.
 */
object DataTypes {

  import Generator.getMembers
  import Generator.genSrc

  /**
   * Generates source file.
   *
   * @return The name of generated file.
   */
  def generate(dir: File, typeM: TypeMapper, ast: List[Stmt]): File = {
    genSrc(dir, "DataTypes") { pw => 
      printTypeList(pw, typeM) 
      printFunctionInterfaces(pw, ast)
    }._1
  }

  /**
   * Prints list of class definition corresponding to tuple.
   */
  private def printTypeList(pw: PrintWriter, typeM: TypeMapper): Unit = {
    for ((t, n) <- typeM.classMap) printType(pw, typeM, t, n)
  }

  /**
   * Prints class definition corresponding to tuple.
   */
  private def printType(pw: PrintWriter, typeM: TypeMapper, dataType: DataType, className: String): Unit = {
    val members = getMembers(dataType).mapValues(typeM.map)

    pw.println("static public class %s implements Serializable {".format(className))

    // Empty Constructor
    pw.println("public %s() {}".format(className))

    // Constructor
    val args = members.map { case (mn, mt) => "%s p_%s".format(mt, mn)}.mkString(", ")
    pw.println("public %s(%s) {".format(className, args))
    for ((mn, _) <- members) {
      pw.println("this.%s = p_%s;".format(mn, mn))
    }
    pw.println("}")

    // toString
    pw.println("public String toString() {")
    pw.println("StringBuilder sb = new StringBuilder();");
    pw.println("sb.append(\"{\");")
    for ( (mn, _) <- members) {
      pw.println("sb.append(%s.toString());".format(mn))
      pw.println("sb.append(\", \");")
    }
    pw.println("sb.append(\"}\");")
    pw.println("return sb.toString();")
    pw.println("}")

    // Fields
    for ( (mn, mt) <- members) {
      pw.println("public %s %s;".format(mt, mn))
    }
    pw.println("}")
  }

  /**
   * Print interfaces for functions.
   */
  private def printFunctionInterfaces(pw: PrintWriter, ast: List[Stmt]): Unit = {
    var maxNArgs = 0
    TreeWalker.walkTree(classOf[Node], ast) {
      case e: BuildInFunction => 
        maxNArgs = maxNArgs.max(e.ftype.argsType.length)
        Success(Unit)
      case e: AnalyzedFuncLit => 
        maxNArgs = maxNArgs.max(e.args.length)
        Success(Unit)
    }

    for (i <- 0 to maxNArgs) {
      pw.println("static interface SCFunction%03d<%s>".format(i, (0 to i).map{"T%d".format(_)}.mkString(", ")))
      pw.println("{")
      pw.println("public T0 invoke(%s);".format((1 to i).map { x => "T%d x%d".format(x, x)}.mkString(", ")))
      pw.println("}")
    }
  }
}
